﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace NGeo.Yahoo.PlaceFinder
{
    /// <summary>
    /// See the <seealso cref="http://developer.yahoo.com/geo/placefinder/guide/requests.html">official 
    /// documentation on Yahoo! PlaceFinder requests</seealso>.
    /// </summary>
    public class Request
    {
        private int _start;
        private int _count;
        private int _offsetMeters;
        //private readonly HashSet<RequestFlag> _flags;
        //private readonly HashSet<RequestGFlag> _gFlags;

        /// <summary>
        /// Create a request with default values: Locale: en-US, FirstIndex: 0, 
        /// MaximumResults: 10, OffsetMeters: 15.
        /// </summary>
        public Request()
        {
            Flags = new HashSet<RequestFlag>();
            GFlags = new HashSet<RequestGFlag>();
            this.ApplyDefaultValues();
        }

        #region Location Parameters

        /// <summary>
        /// A geographical location.
        /// <example>
        /// 701 First Ave., Sunnyvale, CA 94089
        /// </example>
        /// </summary>
        public string Location { get; set; }

        /// <summary>
        /// A Place of Interest (POI) name, Area of Interest (AOI) name, or 
        /// <see cref="http://developer.yahoo.com/geo/placefinder/guide/requests.html#airport-codes">airport 
        /// code</see>. See also <seealso cref="http://developer.yahoo.com/geo/placefinder/guide/requests.html#poi-aoi-names">POI 
        /// and AOI Names</seealso>. Ignored if location parameter is provided.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// <see cref="http://developer.yahoo.com/geo/geoplanet/guide/concepts.html#woeids">Where 
        /// On Earth ID</see>. Must be an integer. Ignored if location or name parameter is provided.
        /// </summary>
        public int? WoeId { get; set; }

        /// <summary>
        /// First line of address (street address or intersection). 
        /// Ignored if location, name, or woeid parameter is provided.
        /// </summary>
        public string Line1 { get; set; }

        /// <summary>
        /// Second line of address (city-state-zip in US). 
        /// Ignored if location, name, or woeid parameter is provided.
        /// </summary>
        public string Line2 { get; set; }

        /// <summary>
        /// Third line of address (postal code in UK). 
        /// Ignored if location, name, or woeid parameter is provided.
        /// </summary>
        public string Line3 { get; set; }

        /// <summary>
        /// House number. Ignored if location, name, woeid, 
        /// or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string HouseNumber { get; set; }

        /// <summary>
        /// Street name. Ignored if location, name, woeid, 
        /// or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string StreetName { get; set; }

        /// <summary>
        /// Unit type, such as apartment (Apt) or suite (Ste). 
        /// Ignored if location, name, woeid, or multi-line (line1/line2/line3) 
        /// parameter is provided.
        /// </summary>
        public string UnitType { get; set; }

        /// <summary>
        /// Unit/Suite/Apartment/Box. Ignored if location, name, woied, 
        /// or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Unit { get; set; }

        /// <summary>
        /// Cross Street name. Ignored if location, name, woeid, 
        /// or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string CrossStreet { get; set; }

        /// <summary>
        /// Postal code. 
        /// Ignored if location, name, woeid, or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Postal { get; set; }

        /// <summary>
        /// Level 4 Administrative name (Neighborhood). Ignored if location, 
        /// name, woeid, or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Level4 { get; set; }

        /// <summary>
        /// Level 3 Administrative name (City/Town/Locality). Ignored if location, 
        /// name, woeid, or multi-line (line1/line2/line3) parameter is provided. 
        /// Do not specify level3 unless level1 or level0 is also specified; otherwise, 
        /// erroneous results might be returned. For best results, specify at least level0 through level3.
        /// </summary>
        public string Level3 { get; set; }

        /// <summary>
        /// Level 2 Administrative name (County). Ignored if location, name, woeid, 
        /// or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Level2 { get; set; }

        /// <summary>
        /// Level 1 Administrative name (State/Province) or abbreviation (US only). 
        /// Ignored if location, name, woeid, or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Level1 { get; set; }

        /// <summary>
        /// Level 0 Administrative name (Country) or country code. Ignored if location, 
        /// name, woeid, or multi-line (line1/line2/line3) parameter is provided.
        /// </summary>
        public string Level0 { get; set; }

        #endregion
        #region Control Parameters

        /// <summary>
        /// Required. The application ID. Grants authorization to use the web service.
        /// </summary>
        public string AppId { get; set; }

        /// <summary>
        /// The language and country. A two-letter ISO-639 major language code and a two-letter ISO-3166-1 alpha-2 country code, 
        /// separated by either a hyphen or underscore. Default is en-US (English/US).
        /// </summary>
        [DefaultValue("en-US")]
        public string Locale { get; set; }

        /// <summary>
        /// Index of first result to return. Range is 0 to 99. Default is 0.
        /// </summary>
        [DefaultValue(0)]
        public int Start
        {
            get { return _start; }
            set
            {
                if (value < 0 || value > 99)
                    throw new ArgumentException("FirstIndex must be between 0 and 99 (inclusive).");
                _start = value;
            }
        }

        /// <summary>
        /// Number of results to return. Range is 1 to 100. Default is 10.
        /// </summary>
        [DefaultValue(10)]
        public int Count
        {
            get { return _count; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentException("MaximumResults must be between 0 and 100 (inclusive).");
                _count = value;
            }
        }

        /// <summary>
        /// Location setback in meters, intended to approximate a building location offset 
        /// from the road center-line. Range is 0 to 100. Default is 15.
        /// </summary>
        [DefaultValue(15)]
        public int OffsetMeters
        {
            get { return _offsetMeters; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentException("OffsetMeters must be between 0 and 100 (inclusive).");
                _offsetMeters = value;
            }
        }

        /// <summary>
        /// String of concatenated characters that specify the data returned. 
        /// The default value of this parameter is an empty string. The default return format is XML. 
        /// See <see cref="http://developer.yahoo.com/geo/placefinder/guide/requests.html#flags-parameter">Flags Parameter</see>.
        /// </summary>
        public HashSet<RequestFlag> Flags { get; set; }

        /// <summary>
        /// String of concatenated characters that specify the geocoding performed. 
        /// The default value of this parameter is an empty string. 
        /// See <see cref="http://developer.yahoo.com/geo/placefinder/guide/requests.html#gflags-parameter">Gflags Parameter</see>.
        /// </summary>
        public HashSet<RequestGFlag> GFlags { get; set; }

        #endregion

        public string GetFlagsAsString()
        {
            var flags = new StringBuilder();

            foreach (var flag in Flags)
                flags.Append(flag.GetEnumMemberAttribute().Value);

            return flags.ToString();
        }

        public virtual string GetGFlagsAsString()
        {
            var gFlags = new StringBuilder();

            foreach (var gFlag in GFlags)
                gFlags.Append(gFlag.GetEnumMemberAttribute().Value);

            return gFlags.ToString();
        }

    }
}
